package com.dianmi.seckill.common.log.impl;

import com.dianmi.seckill.common.log.LogConfiguration;
import com.dianmi.seckill.common.log.LogCutter;
import com.dianmi.seckill.common.log.LogEntity;
import com.dianmi.seckill.common.utils.RandomUtils;
import org.slf4j.MDC;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;

/**
 * @author xieqiaofu
 * @date 2020/11/18
 */
public class LogContext {

    private static volatile LogConfiguration logConfiguration = null;

    private static ThreadLocal<LogContext> holder = new ThreadLocal<>();

    private int entityIndex;

    private int cutterIndex;

    private Map<Integer, LogCutter> cutterCollector = new HashMap<>();

    private String traceId;

    private LogPrinter logPrinter = new LogPrinter(this);

    private LogContext() {}

    public static LogContext getInstance() {
        LogContext context = holder.get();
        if (context == null) {
            context = new LogContext();
            context.generateTraceId();
            holder.set(context);
            return context;
        }
        return context;
    }

    public void log(LogEntity log) {
        this.logPrinter.addLog(log);
        entityIndex++;
    }

    public String getTraceId() {
        return traceId;
    }

    private void generateTraceId() {
        String yyyyMMddHHmmss = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
        String randomNumber = RandomUtils.getRandomNumber(6);
        this.traceId = String.format("%s%s", yyyyMMddHHmmss, randomNumber);
    }

    public LogConfiguration getLogConfiguration() {
        return logConfiguration;
    }

    public static void setLogConfiguration(LogConfiguration logConfiguration) {
        if (LogContext.logConfiguration == null) {
            LogContext.logConfiguration = logConfiguration;
        }
    }

    public int getEntityIndex() {
        return entityIndex;
    }

    public void register(LogCutter cutter) {
        cutterCollector.put(cutterIndex++, cutter);
    }

    public void complete(LogCutter cutter) {
        LogCutter head = cutterCollector.get(0);
        if (head == cutter) {
            MDC.remove("trace_id");
            MDC.remove("method");
            holder.remove();
        }
    }
}
